﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Net.Sockets;
using System.Text;
using System.Globalization;
using Microsoft.Xna.Framework;
using Microsoft.Phone.Info;

namespace TestXNA
{
    public class Sync
    {
        UdpAnySourceMulticastChannel Channel;
        public DateTime sentTime = System.DateTime.Now;
        public DateTime requestTime = System.DateTime.Now;
        string LocalUID = "";
        public double MejorLatencia = 0.0;

        public void CrearListener()
        {
            LocalUID = GetUID();
            this.Channel = new UdpAnySourceMulticastChannel(IPAddress.Parse("224.109.108.108"), 3007);
            this.Channel.PacketReceived += new EventHandler<UdpPacketReceivedEventArgs>(Channel_PacketReceived);
            this.Channel.Open();
        }

        void Channel_PacketReceived(object sender, UdpPacketReceivedEventArgs e)
        {
            DateTime now = System.DateTime.Now;
            string str = e.Message;
            DateTime t;
            System.Diagnostics.Debug.WriteLine("PacketReceived: " + str);

            str = str.Trim('\0');

            // que es lo que recibimos...
            if (str[0] == 'R')
            {
                // request de tiempo
                string uid = str.Substring(1);
                if (uid == LocalUID)
                {
                    System.Diagnostics.Debug.WriteLine("Local UID, ignorando");
                    return;
                }
                SendTime();
            }
            else
                if (str[0] == 'T') // recibimos el tiempo del otro movil
                {
                    t = DateTime.ParseExact(str.Substring(1), "O", CultureInfo.InvariantCulture);

                    if (t == sentTime) // esto es para ignorar si nosotros mismos enviamos
                        return;

                    TimeSpan lat = now - requestTime; // calculemos la latencia
                    double latmsecs = lat.TotalMilliseconds / 2.0; // vamos a asumir que se envió en t/2

                    if (MejorLatencia == 0.0 || latmsecs < MejorLatencia)
                    {
                        MejorLatencia = latmsecs;
                    }
                    else
                        return;

                    TimeSpan ts = (t - now);
                    double msecs = (ts.TotalMilliseconds) + latmsecs;
                    App.ViewModel.ClockOffset = (int)msecs;
                    //App.ViewModel.cameraPosition = new Vector3(2400.0f, 50.0f, 5000.0f);
                    //App.ViewModel.cameraView = new Vector3(2400.0f, 0, 0);
//                    App.ViewModel.Posicion = 2;
                }
                else if (str[0] == 'P')
                {
                    float x = float.Parse(str.Substring(1), CultureInfo.InvariantCulture);
                    App.ViewModel.modelPosition.X = x;
                }
        }

        public static byte[] GetDeviceUniqueID()
        {
            byte[] result = null;
            object uniqueId;
            if (DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueId))
                result = (byte[])uniqueId;

            return result;
        }

        public static string GetUID()
        {
            byte[] uid = GetDeviceUniqueID();

            string s = "";

            for (int i = 0; i < uid.Length; i++)
            {
                s += String.Format("{0:x}", uid[i]);
            }

            return s;
        }

        public void SendTime()
        {
            System.Diagnostics.Debug.WriteLine("SendTime");

            DateTime now = System.DateTime.Now;
            sentTime = now;
            Channel.Send("T" + now.ToString("O"));
        }

        public void RequestTime()
        {
            System.Diagnostics.Debug.WriteLine("RequestTime");

            requestTime = System.DateTime.Now;
            Channel.Send("R{0}", LocalUID);
        }

        public void SendPos(float x)
        {
            System.Diagnostics.Debug.WriteLine("SendPos");
            Channel.Send("P{0}", x.ToString(CultureInfo.InvariantCulture));
        }
    }
}
